#pragma once
#include <iostream>
#include <string>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <cstdlib>
#include "nocopy.hpp"
#include "Log.hpp"
#include "Comm.hpp"
#include "Inetaddr.hpp"

using func_t = std::function<std::string(std::string)>;
// static const std::string default_ip = "0.0.0.0";
static const uint16_t default_port = 8888;

class UdpServer // 聚焦IO
{
public:
    UdpServer(func_t OnMessage, uint16_t port = default_port)
        :_OnMessage(OnMessage), _port(port)
    {
    }

    void Init() // 创建套接字，绑定网络信息
    {
        // 1. 创建socket，打开创建文件细节
        _socketfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_socketfd < 0)
        {
            lg.LogMessage(Fatal, "socket err: %s, %d\n", strerror(errno), errno);
            exit(Socker_Err);
        }

        // 2. 绑定网络信息
        struct sockaddr_in addr;
        memset(&addr, 0, sizeof addr);
        addr.sin_family = AF_INET;
        addr.sin_port = htons(_port);
        // addr.sin_addr.s_addr = inet_addr(_ip.c_str());
        addr.sin_addr.s_addr = INADDR_ANY;
        int n = bind(_socketfd, (struct sockaddr*)&addr, sizeof(addr));
        if(n != 0)
        {
            lg.LogMessage(Fatal, "bind err: %s, %d\n", strerror(errno), errno);
            exit(Bind_Err);
        }
        lg.LogMessage(Info, "%s", "网络通信创建成功");
    }

    void Start() // 启动服务器，接收数据，处理数据
    {
        char buffer[1024];
        for(;;)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            ssize_t n = recvfrom(_socketfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&peer, &len);
            if(n)
            {
                InetAddr addr(peer);
                buffer[n] = 0;
                std::cout << "Cilet say# " << buffer << std::endl;
                // lg.LogMessage(Info, "[%s]:%s", addr.DebugPrint().c_str(), buffer);
                // std::cout << "[" <<  addr.DebugPrint() << "]" << buffer << std::endl; 
                std::string result = _OnMessage(buffer);
                sendto(_socketfd, result.c_str(), result.size(), 0, (struct sockaddr*)&peer, len);
            }
        }
    }
private:
    // std::string _ip;
    uint16_t _port;
    int _socketfd;
    func_t _OnMessage;
};